package org.levi.demo.router;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.*;

public class HostRouterManager implements PathChildrenCacheListener {

    private static final Logger LOG = LoggerFactory.getLogger(HostRouterManager.class);

    public static final String WATCH_PATH = "/demo/dubbo/services";
    //确保多线程操作时，线程之间的可见性
    private volatile Set<String> serviceNodes = new HashSet<String>();

    private static final CuratorFramework zkClient = MyZkClient.getInstance().getZkClient();

    private HostRouterManager(){

        try {
            Stat stat = zkClient.checkExists().forPath(WATCH_PATH);
            if (stat == null) {
                zkClient.create().creatingParentsIfNeeded().forPath(WATCH_PATH);
            }
            PathChildrenCache pathChildrenCache = new PathChildrenCache(zkClient,WATCH_PATH,false);
            pathChildrenCache.getListenable().addListener(this);
            pathChildrenCache.start();
        }catch (Exception e){
            e.printStackTrace();
            LOG.error("创建基础节点失败");
        }
    }

    private static class HostRouterManagerHolder{
        public static HostRouterManager hostRouterManager = new HostRouterManager();
    }

    public static HostRouterManager getInstance() {
        return HostRouterManagerHolder.hostRouterManager;
    }

    /**
     * 提供一个返回service 路径的方法
     * */
     private String getServiceNodeName(String host,String serviceName){
         return serviceName + "_" + host;
     }

    /**
     * 提供一个添加受保护的服务器的方法
     * */
    public void addServiceToGray(String host,String serviceName) throws Exception {
        zkClient.create().creatingParentsIfNeeded().forPath(WATCH_PATH + "/" + getServiceNodeName(host,serviceName));
        LOG.info("当前将{}:{}服务置为发布中状态，服务暂时对消费端隐身",serviceName,host);
    }

    public void removeServiceGrayStatus(String host,String serviceName) throws Exception {
        zkClient.delete().forPath(WATCH_PATH + "/" + getServiceNodeName(host,serviceName));
        LOG.info("服务{}:{}从发布状态中移除，现已对消费者开放",serviceName,host);
    }

    public boolean isCurrentGray(String host,String serviceName){
        if(CollectionUtils.isEmpty(this.serviceNodes)){
            return false;
        }
        return serviceNodes.contains(getServiceNodeName(host,serviceName));
    }

    public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {

        List<String> existNodePath = zkClient.getChildren().forPath(WATCH_PATH);
        if(CollectionUtils.isEmpty(existNodePath)){
            this.serviceNodes = Collections.emptySet();
        }else{
            this.serviceNodes = new HashSet<String>(existNodePath);
        }
    }
}
